<?php

namespace App\Http\Services;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;
use App\Http\Model\Hint;
use App\Http\Model\Game;
use App\Http\Model\Room;
use App\Http\Model\User;
use App\Http\Model\FinanceDiamond;
use App\Http\Model\FinanceUserWallet;
use App\Http\Model\RoomMicro;
use App\Http\Model\RoomHostMicro;
use App\Http\Services\RoomMsgServices;

class GameServices extends CommonServices
{
    protected $gameModel;
    protected $userModel;
    protected $roomModel;
    protected $financeDiamondModel;
    protected $financeUserWalletModel;
    protected $roomMicroModel;
    protected $room_msg_services;
    protected $model_room_hostmicro;

    //每局机器人花费钻石
    public $gameAiDiamond = 2;
    //红队 房间团战队伍1
    public $roomPkTeamMicro1 = [0, 1, 4, 5];
    //蓝队 房间团战队伍2
    public $roomPkTeamMicro2 = [2, 3, 6, 7];
    //房间团战惩罚期持续秒数
    public $roomPkFreeSecond = 90;

    //房间团战用户麦位分数
    protected $roomPkMicroUserScoreKey = 'ROOMPK:MICROUSERSCORE:';//hash ROOMPK:MICROUSERSCORE:{pkId}=>{microId|userId} => {num}
    //房间团战房间配置
    protected $roomPkRoomConfigKey = 'ROOMPK:ROOMCONFIG:';//string ROOMPK:ROOMCONFIG:{roomId} => {json}

    public function __construct()
    {
        parent::__construct();
        $this->gameModel = new Game();
        $this->userModel = new User();
        $this->roomModel = new Room();
        $this->financeDiamondModel = new FinanceDiamond();
        $this->financeUserWalletModel = new FinanceUserWallet();
        $this->roomMicroModel = new RoomMicro();
        $this->model_room_hostmicro = new RoomHostMicro();
        $this->room_msg_services = new RoomMsgServices();

    }

    /**
     * 游戏开始
     */
    public function gameStart($userId, $roomId, $gameType, $aiNum) {
        $code = Hint::SUCCESS;
        $msg = '';
        $data = [];
        do {
            //使用了机器人
            $ai_diamond = $aiNum * $this->gameAiDiamond;
            if($ai_diamond > 0) {
                //用户余额
                $diamondNow = $this->financeUserWalletModel->getUserWalletDiamond($userId);
                if($diamondNow < $ai_diamond) {
                    $code = Hint::DIAMOND_NOT_ENOUGH;
                    break;
                }
            }

            DB::beginTransaction();
            try {
                if($ai_diamond > 0) {
                    $config = config('pay');
                    //钻石
                    $diamond_desc = $config['wallet_change_desc']['diamond_game_ai'];
                    $this->financeDiamondModel->inc($userId, 0, 0, 74, 0-$ai_diamond, $diamond_desc);
                }

                //添加游戏开启记录
                $log = [
                    'game_type' => $gameType,
                    'room_id' => $roomId,
                    'user_id' => $userId,
                    'battle_start_at' => time(),
                    'ai_num' => $aiNum,
                    'ai_diamond' => $ai_diamond,
                ];
                $gameId = $this->gameModel->createGameLog($log);

                //修改房间
                $this->roomModel->setRoomOpenListCache($roomId, 'gameId', $gameId);

                DB::commit();
            } catch (\Exception $e) {
                DB::rollBack();

                write_log('error_game', 'gameStart', ['msg'=>$e->getMessage(), 'line'=>$e->getLine()]);
                $code = Hint::ERR_FAIL;
                break;
            }

            //用户余额
            $data['diamond_num'] = $this->financeUserWalletModel->getUserWalletDiamond($userId);

        } while (false);

        return compact('code', 'msg', 'data');
    }

    /**
     * 游戏结束
     */
    public function gameEnd($userId, $roomId) {
        $code = Hint::SUCCESS;
        $msg = '';
        $data = [];
        do {
            //获取缓存游戏ID
            $gameId = $this->roomModel->getRoomOpenList($roomId, 'gameId');
            if(empty($gameId)) {
                break;
            }
            $info = $this->gameModel->getGameLog($gameId);
            if(empty($info)) {
                break;
            }
            //游戏已结束了
            if(!empty($info['battle_end_at'])) {
                $this->roomModel->setRoomOpenListCache($roomId, 'gameId', 0);
                break;
            }

            DB::beginTransaction();
            try {
                $this->gameModel->updateGameLog($gameId, ['battle_end_at'=>time(), 'battle_duration'=>($info['battle_start_at']-time())]);

                //修改房间
                $this->roomModel->setRoomOpenListCache($roomId, 'gameId', 0);

                DB::commit();
            } catch (\Exception $e) {
                DB::rollBack();

                write_log('error_game', 'gameEnd', ['msg'=>$e->getMessage(), 'line'=>$e->getLine()]);
                $code = Hint::ERR_FAIL;
                break;
            }

        } while (false);

        return compact('code', 'msg', 'data');
    }

    /**
     * 更新游戏数据
     */
    public function reportGameInfo($param) {
        $code = Hint::SUCCESS;
        $msg = '';
        $data = [];
        do {
            //战斗开始通知
            if($param['report_type'] == 'game_start') {
                $roomId = $param['report_msg']['room_id'];
                //获取缓存游戏ID
                $gameId = $this->roomModel->getRoomOpenList($roomId, 'gameId');
                if(empty($gameId)) {
                    break;
                }
                $info = $this->gameModel->getGameLog($gameId);
                if(empty($info)) {
                    break;
                }
                //游戏已结束了
                if(!empty($info['battle_end_at'])) {
                    $this->roomModel->setRoomOpenListCache($roomId, 'gameId', 0);
                    break;
                }
                $upData['mg_id'] = $param['report_msg']['game_round_id'];
                $upData['battle_start_at'] = $param['report_msg']['battle_start_at'];
                $this->gameModel->updateGameLog($gameId, $upData);

                if(!empty($param['report_msg']['players'])) {
                    foreach($param['report_msg']['players'] as $val) {
                        if($val['is_ai'] != 0) {
                            $this->gameModel->createGameUser(['game_id'=>$gameId,'room_id'=>$roomId,'user_id'=>$val['uid']]);
                        }
                    }
                }
            }
            //战斗结算通知
            if($param['report_type'] == 'game_settle') {
                $info = $this->gameModel->getGameLogByMgId($param['report_msg']['game_round_id']);
                if(empty($info)) {
                    break;
                }
                $upData['battle_end_at'] = $param['report_msg']['battle_end_at'];
                $upData['battle_duration'] = $param['report_msg']['battle_duration'];
                $this->gameModel->updateGameLog($info['id'], $upData);

                //更新游戏用户记录
                if(!empty($param['report_msg']['results'])) {
                    foreach($param['report_msg']['results'] as $val) {
                        if($val['is_ai']!=0 && isset($val['rank'])) {
                            $where = [];
                            $where['game_id'] = $info['id'];
                            $where['room_id'] = $info['room_id'];
                            $where['user_id'] = $val['uid'];
                            $upData = [];
                            $upData['rank'] = $val['rank'];
                            $upData['is_escaped'] = $val['is_escaped'];
                            $upData['score'] = $val['score'];
                            $upData['is_win'] = $val['is_win'];
                            $upData['is_managed'] = $val['is_managed'];
                            $this->gameModel->updateGameUser($upData, $where);
                        }
                    }
                }

                //修改房间
                $gameId = $this->roomModel->getRoomOpenList($info['room_id'], 'gameId');
                if(!empty($gameId)) {
                    if($gameId == $info['id']) {
                        $this->roomModel->setRoomOpenListCache($info['room_id'], 'gameId', 0); 
                    }
                }
            }
        } while (false);

        return compact('code', 'msg', 'data');
    }

    /**
     * 开启房间团战
     */
    public function roomPkOpen($userId, $roomId, $battleDuration, $teamName1, $teamName2) {
        $code = Hint::SUCCESS;
        $msg = '';
        $data = [];
        $now = time();
        do {
            $roleCheck = $this->_roomPkCheckUserRole($userId, $roomId);
            if($roleCheck != Hint::SUCCESS) {
                $code = Hint::AUTH_ERROR;
                $msg = '只有房主、管理员 、主持有权利操作哦';
                break;
            }
            //设置缓存
            $roomConfig = [
                'team_name_1' => $teamName1,
                'team_name_2' => $teamName2,
                'battle_duration' => $battleDuration,
            ];
            $chacheKey = $this->roomPkRoomConfigKey.$roomId;
            Redis::SET($chacheKey, json_encode($roomConfig));
            Redis::EXPIRE($chacheKey, 86400);

            //房间模式
            $room_mode = 5;
            $this->roomModel->setRoomMode($roomId, $room_mode);
            $this->room_msg_services->roomModeMsg($roomId, $room_mode, $roomConfig);
            //设置已开启房间信息
            $this->roomModel->setRoomOpenListCache($roomId, 'roomMode', $room_mode);
            $this->roomModel->setRoomOpenListCache($roomId, 'pkId', 0);
            $this->roomModel->setRoomOpenListCache($roomId, 'pkEndTime', 0);

        } while (false);

        return compact('code', 'msg', 'data');
    }

    /**
     * 开始房间团战
     */
    public function roomPkStart($userId, $roomId) {
        $code = Hint::SUCCESS;
        $msg = '';
        $data = [];
        $now = time();
        do {
            $roleCheck = $this->_roomPkCheckUserRole($userId, $roomId);
            if($roleCheck != Hint::SUCCESS) {
                $code = Hint::AUTH_ERROR;
                $msg = '只有房主、管理员 、主持有权利操作哦';
                break;
            }
            //获取缓存房间模式
            $roomMode = $this->roomModel->getRoomOpenList($roomId, 'roomMode');
            if($roomMode != 5) {
                $code = Hint::PARAM_ERROR;
                $msg = '房间不是团战模式';
                break;
            }
            //房间团战房间配置
            $chacheKey = $this->roomPkRoomConfigKey.$roomId;
            $roomConfig = Redis::GET($chacheKey);
            if(empty($roomConfig)) {
                $code = Hint::PARAM_ERROR;
                $msg = '房间挂机时间过长,团战数据已失效,请重新开始';
                break;
            }
            Redis::EXPIRE($chacheKey, 86400);
            $roomConfig = json_decode($roomConfig, true);
            $battleDuration = $roomConfig['battle_duration'];
            $teamName1 = $roomConfig['team_name_1'];
            $teamName2 = $roomConfig['team_name_2'];

            DB::beginTransaction();
            try {
                $pkEndTime = $now + $battleDuration;
                //添加房间团战记录
                $log = [
                    'room_id' => $roomId,
                    'user_id' => $userId,
                    'team_name_1' => $teamName1,
                    'team_score_1' => 0,
                    'team_name_2' => $teamName2,
                    'team_score_2' => 0,
                    'battle_start_at' => $now,
                    'battle_end_at' => $pkEndTime,
                    'battle_duration' => $battleDuration,
                ];
                $pkId = $this->gameModel->createRoomPk($log);

                //修改房间
                $this->roomModel->setRoomOpenListCache($roomId, 'pkId', $pkId);
                $this->roomModel->setRoomOpenListCache($roomId, 'pkEndTime', $pkEndTime);

                DB::commit();
            } catch (\Exception $e) {
                DB::rollBack();

                $code = Hint::ERR_FAIL;
                break;
            }

            //发消息
            $info = $this->gameModel->getRoomPk($pkId);
            $info['pk_id'] = $pkId;
            $info['now_time'] = $now;
            $info['free_time'] = empty($info['battle_end_at']) ? 0 : ($info['battle_end_at'] + $this->roomPkFreeSecond);
            $info['user_log'] = [];
            $this->room_msg_services->roomPkMsg($roomId, 1, $info);

        } while (false);

        return compact('code', 'msg', 'data');
    }

    /**
     * 结束房间团战
     */
    public function roomPkEnd($userId, $roomId) {
        $code = Hint::SUCCESS;
        $msg = '';
        $data = [];
        $now = time();
        do {
            $roleCheck = $this->_roomPkCheckUserRole($userId, $roomId);
            if($roleCheck != Hint::SUCCESS) {
                $code = Hint::AUTH_ERROR;
                $msg = '只有房主、管理员 、主持有权利操作哦';
                break;
            }
            //获取缓存游戏ID
            $pkId = $this->roomModel->getRoomOpenList($roomId, 'pkId');
            if(empty($pkId)) {
                break;
            }
            $info = $this->gameModel->getRoomPk($pkId);
            if(empty($info)) {
                break;
            }
            //游戏已结束了
            if(!empty($info['end_at'])) {
                break;
            }

            DB::beginTransaction();
            try {
                //麦位
                $user_micro_info = $this->roomMicroModel->get_user_micro_status($roomId, $userId);
                $microUserNum = empty($user_micro_info) ? 0 : count($user_micro_info);

                $status = 1;
                if($info['battle_end_at'] > $now) {
                    $status = 2;
                }
                $this->gameModel->updateRoomPk($pkId, ['end_at'=>$now, 'status'=>$status, 'micro_user_num'=>$microUserNum]);

                DB::commit();
            } catch (\Exception $e) {
                DB::rollBack();

                $code = Hint::ERR_FAIL;
                break;
            }

            $userLog = [];
            $cacheKey = $this->roomPkMicroUserScoreKey.$pkId;
            $roomPkMicroUserScoreList = Redis::HGETALL($cacheKey);
            foreach($roomPkMicroUserScoreList as $key=>$val) {
                [$microId, $userId] = explode('|', $key);
                $userLog[$userId]['user_id'] = (int) $userId;
                $userLog[$userId]['teamScore2'] = empty($userLog[$userId]['teamScore2']) ? 0 : $userLog[$userId]['teamScore2'];
                $userLog[$userId]['teamScore1'] = empty($userLog[$userId]['teamScore1']) ? 0 : $userLog[$userId]['teamScore1'];
                if(in_array($microId, $this->roomPkTeamMicro2)) {
                    $userLog[$userId]['teamScore2'] = $userLog[$userId]['teamScore2'] + $val;
                }else{
                    $userLog[$userId]['teamScore1'] = $userLog[$userId]['teamScore1'] + $val;
                }
            }

            //记录结束时间
            $this->roomModel->setRoomOpenListCache($roomId, 'pkEndTime', $now);

            //发消息
            $info = $this->gameModel->getRoomPk($pkId);
            $info['pk_id'] = $pkId;
            $info['now_time'] = $now;
            $info['free_time'] = empty($info['battle_end_at']) ? 0 : ($info['battle_end_at'] + $this->roomPkFreeSecond);
            $info['user_log'] = array_values($userLog);
            $this->room_msg_services->roomPkMsg($roomId, 2, $info);

        } while (false);

        return compact('code', 'msg', 'data');
    }

    /**
     * 房间送礼物房间团战处理
     * giftNum 礼物数量
     * diamondTotal 每收礼用户的礼物价值总钻石数
     */
    public function roomSendGiftForGameHandle($roomId, $fromUserId, $toUserIds, $giftNum, $diamondTotal) {
        $now = time();
        do {
            if(empty($roomId)) {
                break;
            }
            if(empty($toUserIds)) {
                break;
            }
            if(empty($diamondTotal)) {
                break;
            }
            //获取缓存房间模式
            $roomMode = $this->roomModel->getRoomOpenList($roomId, 'roomMode');
            if($roomMode != 5) {
                break;
            }
            //获取缓存游戏ID
            $pkId = $this->roomModel->getRoomOpenList($roomId, 'pkId');
            if(empty($pkId)) {
                break;
            }
            //结束时间
            $pkEndTime = $this->roomModel->getRoomOpenList($roomId, 'pkEndTime');
            if(empty($pkEndTime) || $pkEndTime<=$now) {
                break;
            }
            //整理数据
            $teamScore1 = 0;
            $teamScore2 = 0;
            $logList = [];
            foreach($toUserIds as $userId) {
                //麦位
                $user_micro_info = $this->roomMicroModel->get_user_micro_status($roomId, $userId);
                //没在麦位
                if(empty($user_micro_info)) {
                    continue;
                }
                $microId = $user_micro_info['micro_id'];
                if(in_array($microId, $this->roomPkTeamMicro2)) {
                    $teamType = 2;
                    $teamScore2 = $teamScore2 + $diamondTotal;
                }else{
                    $teamType = 1;
                    $teamScore1 = $teamScore1 + $diamondTotal;
                }

                $logList[] = [
                    'room_id' => $roomId,
                    'user_id' => $userId,
                    'pk_id' => $pkId,
                    'micro_id' => $microId,
                    'score' => $diamondTotal,
                    'team_type' => $teamType,
                ];
            }

            DB::beginTransaction();
            try {
                //添加房间团战用户记录
                foreach($logList as $val) {
                    $this->gameModel->createRoomPkUserLog($val);
                }
                //累计房间团战记录
                $this->gameModel->incrRoomPk($pkId, 'team_score_1', $teamScore1);
                $this->gameModel->incrRoomPk($pkId, 'team_score_2', $teamScore2);

                DB::commit();
            } catch (\Exception $e) {
                DB::rollBack();
                write_log('error_game', 'roomSendGiftForGameHandle', [[$roomId, $fromUserId, $toUserIds, $giftNum, $diamondTotal], 'msg'=>$e->getMessage(), 'line'=>$e->getLine()]);

                break;
            }

            //缓存
            //累计房间团战用户记录
            $cacheKey = $this->roomPkMicroUserScoreKey.$pkId;
            foreach($logList as $val) {
                Redis::HINCRBY($cacheKey, $val['micro_id'].'|'.$val['user_id'], $val['score']);
            }
            Redis::expire($cacheKey, 7200);

            $info = $this->gameModel->getRoomPk($pkId);
            if(empty($info)) {
                break;
            }

            $userLog = [];
            $roomPkMicroUserScoreList = Redis::HGETALL($cacheKey);
            foreach($roomPkMicroUserScoreList as $key=>$val) {
                [$microId, $userId] = explode('|', $key);
                $userLog[$userId]['user_id'] = $userId;
                $userLog[$userId]['teamScore2'] = empty($userLog[$userId]['teamScore2']) ? 0 : $userLog[$userId]['teamScore2'];
                $userLog[$userId]['teamScore1'] = empty($userLog[$userId]['teamScore1']) ? 0 : $userLog[$userId]['teamScore1'];
                if(in_array($microId, $this->roomPkTeamMicro2)) {
                    $userLog[$userId]['teamScore2'] = $userLog[$userId]['teamScore2'] + $val;
                }else{
                    $userLog[$userId]['teamScore1'] = $userLog[$userId]['teamScore1'] + $val;
                }
            }

            //发消息
            $info['pk_id'] = $pkId;
            $info['now_time'] = $now;
            $info['free_time'] = empty($info['battle_end_at']) ? 0 : ($info['battle_end_at'] + $this->roomPkFreeSecond);
            $info['user_log'] = array_values($userLog);
            $this->room_msg_services->roomPkMsg($roomId, 3, $info);

        } while (false);
    }

    /**
     * 房间团战详情
     */
    public function roomPkInfo($userId, $roomId) {
        $code = Hint::SUCCESS;
        $msg = '';
        $data = [];
        $now = time();
        do {
            //获取缓存游戏ID
            $pkId = $this->roomModel->getRoomOpenList($roomId, 'pkId');
            if(empty($pkId)) {
                break;
            }
            $info = $this->gameModel->getRoomPk($pkId);
            if(empty($info)) {
                break;
            }

            $userLog = [];
            $cacheKey = $this->roomPkMicroUserScoreKey.$pkId;
            $roomPkMicroUserScoreList = Redis::HGETALL($cacheKey);
            foreach($roomPkMicroUserScoreList as $key=>$val) {
                [$microId, $userId] = explode('|', $key);
                $userLog[$userId]['user_id'] = (int) $userId;
                $userLog[$userId]['teamScore2'] = empty($userLog[$userId]['teamScore2']) ? 0 : $userLog[$userId]['teamScore2'];
                $userLog[$userId]['teamScore1'] = empty($userLog[$userId]['teamScore1']) ? 0 : $userLog[$userId]['teamScore1'];
                if(in_array($microId, $this->roomPkTeamMicro2)) {
                    $userLog[$userId]['teamScore2'] = $userLog[$userId]['teamScore2'] + $val;
                }else{
                    $userLog[$userId]['teamScore1'] = $userLog[$userId]['teamScore1'] + $val;
                }
            }

            //发消息
            $info['pk_id'] = $pkId;
            $info['user_log'] = array_values($userLog);

            $data = $info;

        } while (false);

        if(empty($data['pk_id'])) {
            $data['pk_id'] = 0;
            //房间团战房间配置
            $chacheKey = $this->roomPkRoomConfigKey.$roomId;
            $roomConfig = Redis::GET($chacheKey);
            if(empty($roomConfig)) {
                $code = Hint::PARAM_ERROR;
                $msg = '房间挂机时间过长,团战数据已失效,请重新开始';
            }else{
                Redis::EXPIRE($chacheKey, 86400);
                $roomConfig = json_decode($roomConfig, true);
                $data['battle_duration'] = $roomConfig['battle_duration'];
                $data['team_name_1'] = $roomConfig['team_name_1'];
                $data['team_name_2'] = $roomConfig['team_name_2'];
            }
        }
        $data['now_time'] = $now;
        $data['free_time'] = empty($data['battle_end_at']) ? 0 : ($data['battle_end_at'] + $this->roomPkFreeSecond);

        return compact('code', 'msg', 'data');
    }

    /**
     * 房间团战用户权限校验
     */
    public function _roomPkCheckUserRole($userId, $roomId) {
        $code = Hint::ERROR;

        do {
            //获取用户房间权限
            $role = $this->roomModel->get_role($roomId, $userId);
            if ($role > 0) {
                return Hint::SUCCESS;
            }
            //判断是否主持麦
            $micro_user_id = $this->model_room_hostmicro->get_user_id($roomId);
            if($micro_user_id == $userId) {
                return Hint::SUCCESS;
            }

        } while (false);

        return $code;
    }




}
